import cv2
import json
import time
from Mysql import MySQL
import configparser
from difflib import get_close_matches
from aip import AipOcr
from aip import AipSpeech
from unihiker import GUI, Audio
from pinpong.board import Board, Pin
from pinpong.extension.unihiker import *
import numpy as np
from pinpong.board import Servo
from pinpong.extension.unihiker import button_a, button_b
import random
import threading
import time
from tkinter import *
gui = GUI()

audio = Audio()

Board().begin()

""" 你的 APPID AK SK """

SPEECH_APP_ID = "116078860"
SPEECH_API_KEY = "0fwYDPyARqNhILeH9VOWvTlr"
SPEECH_SECRET_KEY = "hgJPbidNvopGLKUjqdmjbpaY6H3Q79sn"

ORC_APP_ID = "116015521"
ORC_API_KEY = "PZj84fTDt3CqmBkw1BCIWktP"
ORC_SECRET_KEY = "vypcTlcGXEiVXTLWcb3QO4dqIZ7i6z8E"

info_text1 = gui.draw_text(x=80, y=250, color="red", font_size=12, text="")
info_text2 = gui.draw_text(x=80, y=280, color="red", font_size=12, text="")
#配置文件读入
config = configparser.ConfigParser() 
config.read('config.ini')

g_image_count = config['General'].getint('image_count')
g_speech_count = config['General'].getint('speech_count')
g_run = True

g_answer = ""
servo1 = Servo(Pin((Pin.P8)))
servo2 = Servo(Pin((Pin.P16)))
angle1 = 90
angle2 = 90
pin_led = Pin(Pin.P7, Pin.OUT)
pin_led.write_digital(1)

def Record():
    print("录音！")
    global g_speech_count, config
    
    # 初始状态更新
    info_text1.config(x=80, y=250,text="开始录音...")
    
    def do_record():
        global g_speech_count, config
        try:
            # 开始录音
            audio.record(f'audio/speech_{g_speech_count}.wav', 6)
            info_text1.config(x=80, y=250,text="录音结束")
            time.sleep(1)
            info_text1.config(x=80, y=250,text="正在识别语音...")
            g_speech_count += 1
            config['General']['speech_count'] = f"{g_speech_count}"   
            with open('config.ini', 'w') as configfile:  
                config.write(configfile)      
            Recognition()
            
        except Exception as e:
            print(f"录音发生错误: {str(e)}")
            info_text1.config(x=80, y=250,text="录音失败，请重试")
    
    # 创建并启动录音线程
    record_thread = threading.Thread(target=do_record)
    record_thread.start()

def Search():
    global angle1, angle2
    if g_answer == "":
        info_text1.config(x=80, y=250,text="语音识别失败！") 
    else:
        sql = MySQL("BookDetect.db")
        res = sql.SearchTableAngle(g_answer)
        print(res)
        servo1.write_angle(res[1])
        servo2.write_angle(res[2])
        
def Recognition():
    print("开始识别！")
    global g_speech_count, g_answer
    audioWav = None  # 初始化 audioWav 变量
    try:  
        with open(f'audio/speech_5.wav', 'rb') as file:
            audioWav = file.read()
    except FileNotFoundError:
        info_text1.config(x=80, y=250,text="没有找到音频文件！请先录音再进行语言识别！") 
        time.sleep(1)
        return  # 退出函数
    except Exception as e:  
        info_text1.config(x=80, y=250,text="未知错误！")
        time.sleep(1)
        return  # 退出函数

    client = AipSpeech(SPEECH_APP_ID, SPEECH_API_KEY, SPEECH_SECRET_KEY)
    res = client.asr(audioWav, 'wav', 16000, { 'dev_pid': 1537, })
    print(res)
    answer = res["result"][0]
    if answer:
        g_answer = answer[:-1]  
    else:  
        g_answer = answer
    print(g_answer)
    info_text1.config(x=80, y=250,text=g_answer)
    time.sleep(1)
    Search()

def Learn(): 
    sql = MySQL("BookDetect.db")
    print("开始学习！")
    result = []

    global g_image_count
    ocr = AipOcr(ORC_APP_ID, ORC_API_KEY, ORC_SECRET_KEY)
    with open(f'image/image_2.png', 'rb') as file:  
        image = file.read()
    result = ocr.accurate(image)
    print("返回数据成功！")
    print(result)
    
    # 提取所有书名和对应的位置信息
    book_info = {item['words']: item['location'] for item in result['words_result']}
    data = []    
    result.clear()
    for book_name, book_location in book_info.items():
        if len(book_name) <= 1:
            continue
        if book_name[1] == '法' or book_name[1] == '英':
            continue
        if (book_name[0] >= 'a' and book_name[0] <= 'z') or (book_name[0] >= 'A' and book_name[0] <= 'Z'):
            continue
    
        book_left = book_location['left']
        book_top = book_location['top']
        
        data.append((book_name, book_top, book_left))
        print(data)
        if sql.SearchTableBook(book_name) == None:
            sql.InsertTableBook(data)
        data.clear()
    
    sql.SelectTableBook()
    info_text1.config(x=80, y=250, text="学习成功！") 
    print("学习成功！")
    Main_GUI_Init()

def CaptureImages():
    print("打开摄像头",flush=True)
    gui.clear()
    cap = cv2.VideoCapture(0)
    
    # 设置更高的分辨率
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)  # 提高分辨率到1280x720
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
    cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
    # 设置其他相机参数以提高图像质量
    cap.set(cv2.CAP_PROP_AUTOFOCUS, 1)  # 启用自动对焦
    cap.set(cv2.CAP_PROP_BRIGHTNESS, 20)  # 调整亮度
    cap.set(cv2.CAP_PROP_CONTRAST, 50)  # 提高对比度
    cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.25) # 关闭自动曝光
    
    cv2.namedWindow('camera',cv2.WND_PROP_FULLSCREEN)    #窗口全屏
    cv2.setWindowProperty('camera', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)   #窗口全屏

    global g_image_count, config
    press_start = 0
    while cap.isOpened():
        success, image = cap.read()
        if not success:
            print("Ignoring empty camera frame.")
            continue
        
        # image = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE) #旋转屏幕
        # image = usm(image, 10.0)  # number参数是高斯核的标准差sigma

        cv2.imshow('camera', image)
        
        key = cv2.waitKey(5) & 0xFF

        if key == ord('a'):
            if press_start == 0:
                press_start = time.time()
            elif time.time() - press_start >= 1.0:  
                print("长按检测到，开始学习...")
                cap.release()
                Learn()
                break
        else:
            if press_start > 0:
                print(time.time() - press_start)
                if time.time() - press_start < 1.0:  # 短按
                    g_image_count += 1
                    filename = f'image/image_{g_image_count}.png'
                    cv2.imwrite(filename, image, [int(cv2.IMWRITE_PNG_COMPRESSION), 0])
                    print(f'保存图片: image/image_{g_image_count}')
                press_start = 0
                
        if key == ord('b'):
            break
    
    cap.release()
    cv2.destroyAllWindows()
    
    config['General']['image_count'] = f"{g_image_count}"   
    with open('config.ini', 'w') as configfile:  
        config.write(configfile)  
    print(f'保存配置文件成功')
    Main_GUI_Init()

def Quit():
    print("退出程序！")
    global g_run
    g_run = False

def ServoTest1():
    print("left-right")
    global angle1, servo1
    
    while True:
        if button_a.is_pressed():
            if angle1 < 180:
                angle1 += 3
                if angle1 >= 180:
                    angle1 == 180
                servo1.write_angle(angle1)
                print(f"Angle increased to: {angle1}")
                time.sleep(0.1)
                
        if button_b.is_pressed():  # 按键B减少角度
            if angle1 > 0:
                angle1 -= 3
                if angle1 <= 0:
                    angle1 == 0
                servo1.write_angle(angle1)
                print(f"Angle decreased to: {angle1}")
                time.sleep(0.1)  # 防止按键太敏感
                
        if button_a.is_pressed() and button_b.is_pressed():
            time.sleep(1)  # 等待1秒确认是长按
            if button_a.is_pressed() and button_b.is_pressed():
                print("退出左右调节")   
                break
    Main_GUI_Init()

def ServoTest2():
    print("舵机控制")
    global angle2, servo2
    
    while True:
        if button_a.is_pressed():
            if angle2 < 180:
                angle2 += 3
                if angle2 >= 180:
                    angle2 == 180
                servo2.write_angle(angle2)
                print(f"Angle increased to: {angle2}")
                time.sleep(0.1)
                
        if button_b.is_pressed():  # 按键B减少角度
            if angle2 > 0:
                angle2 -= 3
                if angle2 <= 0:
                    angle2 == 0
                servo2.write_angle(angle2)
                print(f"Angle decreased to: {angle2}")
                time.sleep(0.1)  # 防止按键太敏感
                
        if button_a.is_pressed() and button_b.is_pressed():
            time.sleep(1)  # 等待1秒确认是长按
            if button_a.is_pressed() and button_b.is_pressed():
                print("退出上下调节")
                break
    Main_GUI_Init()

def AngleStore():
    sql = MySQL("BookDetect.db")
    global angle1, angle2, g_answer
    data = []
    data.append((g_answer, angle1, angle2))
    sql.InsertTableAngle(data)
    sql.SelectTableAngle()
    print("保存成功")
# def AngleStore():

def Main_GUI_Init():
    global info_text1
    info_text1 = gui.draw_text(x=80, y=250, color="red", font_size=12, text="")
    gui.draw_text(x=20, y=10, color="#4169E1", font_size=18,text="图像识别图书助手")
    gui.add_button(x=60, y=100, w=100, h=30, text="拍照", origin='center', onclick=lambda: CaptureImages())
    gui.add_button(x=180, y=100, w=100, h=30, text="上下控制", origin='center', onclick=lambda: ServoTest2())
    gui.add_button(x=60, y=160, w=100, h=30, text="录音", origin='center', onclick=lambda: Record())
    gui.add_button(x=180, y=160, w=100, h=30, text="左右控制", origin='center', onclick=lambda: ServoTest1())
    gui.add_button(x=60, y=220, w=100, h=30, text="查询", origin='center', onclick=lambda: Recognition())
    gui.add_button(x=180, y=220, w=100, h=30, text="退出", origin='center', onclick=lambda: Quit())
    gui.add_button(x=60, y=280, w=100, h=30, text="保存角度", origin='center', onclick=lambda: AngleStore())
    gui.add_button(x=180, y=280, w=100, h=30, text="学习", origin='center', onclick=lambda: Learn())

def test_camera_resolutions():
    cap = cv2.VideoCapture(0)
    
    # 常见分辨率列表
    resolutions = [
        (640, 480),    # VGA
        (1280, 720),   # HD
        (1920, 1080),  # Full HD
        (2560, 1440),  # 2K
        (3840, 2160)   # 4K
    ]
    
    print("测试摄像头支持的分辨率：")
    for width, height in resolutions:
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
        
        actual_width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
        actual_height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
        
        if actual_width == width and actual_height == height:
            print(f"✓ {width}x{height} 支持")
        else:
            print(f"✗ {width}x{height} 不支持 (实际: {actual_width}x{actual_height})")
    
    cap.release()

if __name__ == "__main__":
    test_camera_resolutions()
    Main_GUI_Init()
    while True:            
        if g_run == False:                
            break
        time.sleep(1)